home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / share / pyshared / parted / disk.py < prev    next >
Encoding:
Python Source  |  2010-06-29  |  17.1 KB  |  489 lines

  1. #
  2. # disk.py
  3. # Python bindings for libparted (built on top of the _ped Python module).
  4. #
  5. # Copyright (C) 2009  Red Hat, Inc.
  6. #
  7. # This copyrighted material is made available to anyone wishing to use,
  8. # modify, copy, or redistribute it subject to the terms and conditions of
  9. # the GNU General Public License v.2, or (at your option) any later version.
  10. # This program is distributed in the hope that it will be useful, but WITHOUT
  11. # ANY WARRANTY expressed or implied, including the implied warranties of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
  13. # Public License for more details.  You should have received a copy of the
  14. # GNU General Public License along with this program; if not, write to the
  15. # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. # 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
  17. # source code or documentation are not subject to the GNU General Public
  18. # License and may only be used or replicated with the express permission of
  19. # Red Hat, Inc.
  20. #
  21. # Red Hat Author(s): David Cantrell <dcantrell@redhat.com>
  22. #
  23.  
  24. import _ped
  25. import parted
  26.  
  27. from cachedlist import CachedList
  28. from decorators import localeC
  29.  
  30. class Disk(object):
  31.     """Disk()
  32.  
  33.        A Disk object describes a type of device in the system.  Disks
  34.        can hold partitions.  A Disk is a basic operating system-specific
  35.        object."""
  36.     @localeC
  37.     def __init__(self, device=None, PedDisk=None):
  38.         """Create a new Disk object from the device and type specified.  The
  39.            device is a Device object and type is a string matching a key in
  40.            the diskType hash."""
  41.         if PedDisk:
  42.             self.__disk = PedDisk
  43.  
  44.             if device is None:
  45.                 self._device = parted.Device(PedDevice=self.__disk.dev)
  46.             else:
  47.                 self._device = device
  48.         elif device is None:
  49.             raise parted.DiskException, "no device specified"
  50.         else:
  51.             self.__disk = _ped.Disk(device.getPedDevice())
  52.             self._device = device
  53.  
  54.         self._partitions = CachedList(lambda : self.__getPartitions())
  55.  
  56.     def _hasSameParts(self, other):
  57.         import itertools
  58.  
  59.         if len(self.partitions) != len(other.partitions):
  60.             return False
  61.  
  62.         partIter = itertools.izip(self.partitions, other.partitions)
  63.         while True:
  64.             try:
  65.                 (left, right) = partIter.next()
  66.                 if left != right:
  67.                     return False
  68.             except StopIteration:
  69.                 return True
  70.  
  71.     def __eq__(self, other):
  72.         return not self.__ne__(other)
  73.  
  74.     def __ne__(self, other):
  75.         if hash(self) == hash(other):
  76.             return False
  77.  
  78.         if type(self) != type(other):
  79.             return True
  80.  
  81.         return self.device != other.device or not self._hasSameParts(other)
  82.  
  83.     def __str__(self):
  84.         s = ("parted.Disk instance --\n"
  85.              "  type: %(type)s  primaryPartitionCount: %(primaryCount)s\n"
  86.              "  lastPartitionNumber: %(last)s  maxPrimaryPartitionCount: %(max)s\n"
  87.              "  partitions: %(partitions)s\n"
  88.              "  device: %(device)r\n"
  89.              "  PedDisk: %(ped)r" %
  90.              {"type": self.type, "primaryCount": self.primaryPartitionCount,
  91.               "last": self.lastPartitionNumber, "max": self.maxPrimaryPartitionCount,
  92.               "partitions": self.partitions, "device": self.device,
  93.               "ped": self.__disk})
  94.         return s
  95.  
  96.     def __getPartitions(self):
  97.         """Construct a list of partitions on the disk.  This is called only as
  98.            needed from the self.partitions property, which just happens to be
  99.            a CachedList."""
  100.         partitions = []
  101.         partition = self.getFirstPartition()
  102.  
  103.         while partition:
  104.             if partition.type & parted.PARTITION_FREESPACE or \
  105.                partition.type & parted.PARTITION_METADATA or \
  106.                partition.type & parted.PARTITION_PROTECTED:
  107.                 partition = partition.nextPartition()
  108.                 continue
  109.  
  110.             partitions.append(partition)
  111.             partition = partition.nextPartition()
  112.  
  113.         return partitions
  114.  
  115.     @property
  116.     @localeC
  117.     def primaryPartitionCount(self):
  118.         """The number of primary partitions on this disk."""
  119.         return self.__disk.get_primary_partition_count()
  120.  
  121.     @property
  122.     @localeC
  123.     def lastPartitionNumber(self):
  124.         """The last assigned partition number currently on this disk."""
  125.         return self.__disk.get_last_partition_num()
  126.  
  127.     @property
  128.     @localeC
  129.     def maxPrimaryPartitionCount(self):
  130.         """The maximum number of primary partitions allowed on this disk."""
  131.         return self.__disk.get_max_primary_partition_count()
  132.  
  133.     @property
  134.     @localeC
  135.     def maxSupportedPartitionCount(self):
  136.         """The maximum number of partitions allowed on this disk."""
  137.         return self.__disk.get_max_supported_partition_count()
  138.  
  139.     @property
  140.     @localeC
  141.     def partitionAlignment(self):
  142.         """Partition start address Alignment."""
  143.         alignment = self.__disk.get_partition_alignment()
  144.         return parted.Alignment(PedAlignment=alignment)
  145.  
  146.     @property
  147.     @localeC
  148.     def maxPartitionLength(self):
  149.         """Max Partition Length the disk's label can represent."""
  150.         return self.__disk.max_partition_length()
  151.  
  152.     @property
  153.     @localeC
  154.     def maxPartitionStartSector(self):
  155.         """Max Partition Start Sector the disk's label can represent."""
  156.         return self.__disk.max_partition_start_sector()
  157.  
  158.     @localeC
  159.     def getFlag(self, flag):
  160.         """Get the value of a particular flag on the disk.  Valid flags
  161.            are the _ped.DISK_* constants.  See _ped.disk_flag_get_name() and
  162.            _ped.disk_flag_get_by_name() for more help working with disk flags.
  163.         """
  164.         return self.__disk.get_flag(flag)
  165.  
  166.     @localeC
  167.     def setFlag(self, flag):
  168.         """Set the flag on this disk.  On error, an Exception will be raised.
  169.            See getFlag() for more help on working with disk flags."""
  170.         return self.__disk.set_flag(flag, 1)
  171.  
  172.     @localeC
  173.     def unsetFlag(self, flag):
  174.         """Unset the flag on this disk.  On error, an Exception will be raised.
  175.            See getFlag() for more help on working with disk flags."""
  176.         return self.__disk.set_flag(flag, 0)
  177.  
  178.     @localeC
  179.     def isFlagAvailable(self, flag):
  180.         """Return True if flag is available on this Disk, False
  181.            otherwise."""
  182.         return self.__disk.is_flag_available(flag)
  183.  
  184.     @property
  185.     def partitions(self):
  186.         """The list of partitions currently on this disk."""
  187.         return self._partitions
  188.  
  189.     @property
  190.     def device(self):
  191.         """The underlying Device holding this disk and partitions."""
  192.         return self._device
  193.  
  194.     type = property(lambda s: s.__disk.type.name, lambda s, v: setattr(s.__disk, "type", parted.diskType[v]))
  195.  
  196.     @localeC
  197.     def duplicate(self):
  198.         """Make a deep copy of this Disk."""
  199.         return Disk(PedDisk=self.__disk.duplicate())
  200.  
  201.     @localeC
  202.     def destroy(self):
  203.         """Closes the Disk ensuring all outstanding writes are flushed."""
  204.         return self.__disk.destroy()
  205.  
  206.     @localeC
  207.     def commit(self):
  208.         """Writes in-memory changes to a partition table to disk and
  209.            informs the operating system of the changes.  Equivalent to
  210.            calling self.commitToDevice() then self.commitToOS()."""
  211.         self.partitions.invalidate()
  212.  
  213.         return self.__disk.commit()
  214.  
  215.     @localeC
  216.     def commitToDevice(self):
  217.         """Write the changes made to the in-memory description of a
  218.            partition table to the device."""
  219.         self.partitions.invalidate()
  220.  
  221.         return self.__disk.commit_to_dev()
  222.  
  223.     @localeC
  224.     def commitToOS(self):
  225.         """Tell the operating system kernel about the partition table
  226.            layout of this Disk."""
  227.         self.partitions.invalidate()
  228.  
  229.         return self.__disk.commit_to_os()
  230.  
  231.     @localeC
  232.     def check(self):
  233.         """Perform a sanity check on the partition table of this Disk."""
  234.         return self.__disk.check()
  235.  
  236.     @localeC
  237.     def supportsFeature(self, feature):
  238.         """Check that the disk type supports the provided feature."""
  239.         return self.__disk.type.check_feature(feature)
  240.  
  241.     @localeC
  242.     def addPartition(self, partition=None, constraint=None):
  243.         """Add a new Partition to this Disk with the given Constraint."""
  244.         if constraint:
  245.             result = self.__disk.add_partition(partition.getPedPartition(),
  246.                                                constraint.getPedConstraint())
  247.         elif not partition:
  248.             raise parted.DiskException, "no partition or constraint specified"
  249.         else:
  250.             result = self.__disk.add_partition(partition.getPedPartition())
  251.  
  252.         if result:
  253.             partition.geometry = parted.Geometry(PedGeometry=partition.getPedPartition().geom)
  254.             self.partitions.invalidate()
  255.             return True
  256.         else:
  257.             return False
  258.  
  259.     @localeC
  260.     def removePartition(self, partition=None):
  261.         """Removes specified Partition from this Disk.  NOTE:  If the
  262.            Partition is an extended partition, it must not contain any
  263.            logical partitions.  Also note that the partition is not
  264.            actually destroyed unless you use the deletePartition()
  265.            method."""
  266.         if not partition:
  267.             raise parted.DiskException, "no partition specified"
  268.  
  269.         if self.__disk.remove_partition(partition.getPedPartition()):
  270.             self.partitions.invalidate()
  271.             return True
  272.         else:
  273.             return False
  274.  
  275.     @localeC
  276.     def deletePartition(self, partition):
  277.         """Removes specified Partition from this Disk under the same
  278.            conditions as removePartition(), but also destroy the
  279.            removed Partition."""
  280.         if self.__disk.delete_partition(partition.getPedPartition()):
  281.             self.partitions.invalidate()
  282.             return True
  283.         else:
  284.             return False
  285.  
  286.     @localeC
  287.     def deleteAllPartitions(self):
  288.         """Removes and destroys all Partitions in this Disk."""
  289.         if self.__disk.delete_all():
  290.             self.partitions.invalidate()
  291.             return True
  292.         else:
  293.             return False
  294.  
  295.     @localeC
  296.     def setPartitionGeometry(self, partition=None, constraint=None, start=None, end=None):
  297.         """Sets the Geometry of the specified Partition using the given
  298.            Constraint and start and end sectors.  Note that this method
  299.            does not modify the partition contents, just the partition
  300.            table."""
  301.         if not partition or not constraint:
  302.             raise parted.DiskException, "no partition or constraint specified"
  303.  
  304.         if not start or not end:
  305.             raise parted.DiskException, "no start or end geometry specified"
  306.  
  307.         return self.__disk.set_partition_geom(partition.getPedPartition(),
  308.                                               constraint.getPedConstraint(),
  309.                                               start, end)
  310.  
  311.     @localeC
  312.     def maximizePartition(self, partition=None, constraint=None):
  313.         """Grow the Partition's Geometry to the maximum possible subject
  314.            to Constraint."""
  315.         if not partition:
  316.             raise parted.DiskException, "no partition specified"
  317.  
  318.         if constraint:
  319.             return self.__disk.maximize_partition(partition.getPedPartition(),
  320.                                                   constraint.getPedConstraint())
  321.         else:
  322.             return self.__disk.maximize_partition(partition.getPedPartition())
  323.  
  324.     @localeC
  325.     def calculateMaxPartitionGeometry(self, partition=None, constraint=None):
  326.         """Get the maximum Geometry the Partition can be grown to,
  327.            subject to the given Constraint."""
  328.         if not partition:
  329.             raise parted.DiskException, "no partition specified"
  330.  
  331.         if constraint:
  332.             return parted.Geometry(PedGeometry=self.__disk.get_max_partition_geometry(partition.getPedPartition(), constraint.getPedConstraint()))
  333.         else:
  334.             return parted.Geometry(PedGeometry=self.__disk.get_max_partition_geometry(partition.getPedPartition()))
  335.  
  336.     @localeC
  337.     def minimizeExtendedPartition(self):
  338.         """Reduce the size of the extended partition to a minimum while
  339.            still wrapping its logical partitions.  If there are no logical
  340.            partitions, remove the extended partition."""
  341.         ret = self.__disk.minimize_extended_partition()
  342.  
  343.         if ret:
  344.             self.partitions.invalidate()
  345.  
  346.         return ret
  347.  
  348.     @localeC
  349.     def getPartitionBySector(self, sector):
  350.         """Returns the Partition that contains the sector.  If the sector
  351.            lies within a logical partition, then the logical partition is
  352.            returned (not the extended partition)."""
  353.         return parted.Partition(disk=self, PedPartition=self.__disk.get_partition_by_sector(sector))
  354.  
  355.     def getMaxLogicalPartitions(self):
  356.         """Return the maximum number of logical partitions this Disk
  357.            will hold.  Returns 0 if there is no extended partition on
  358.            the disk, returns 11 when all else fails."""
  359.         if not self.supportsFeature(parted.DISK_TYPE_EXTENDED):
  360.             return 0
  361.  
  362.         # maximum number of logical partitions per device type
  363.         maxLogicalPartitionCount = {
  364.             "hd": 59,
  365.             "sd": 11,
  366.             "ataraid/": 11,
  367.             "rd/": 3,
  368.             "cciss/": 11,
  369.             "i2o/": 11,
  370.             "iseries/vd": 3,
  371.             "ida/": 11,
  372.             "sx8/": 11,
  373.             "xvd": 11,
  374.             "vd": 11,
  375.             "mmcblk": 5
  376.         }
  377.  
  378.         dev = self.device.path[5:]
  379.         for key in maxLogicalPartitionCount.keys():
  380.             if dev.startswith(key):
  381.                 return maxLogicalPartitionCount[key]
  382.  
  383.         # XXX: if we don't know about it, should we pretend it can't have
  384.         # logicals?  probably safer to just use something reasonable
  385.         return 11
  386.  
  387.     @localeC
  388.     def getExtendedPartition(self):
  389.         """Return the extended Partition, if any, on this Disk."""
  390.         try:
  391.             return parted.Partition(disk=self, PedPartition=self.__disk.extended_partition())
  392.         except:
  393.             return None
  394.  
  395.     def __filterPartitions(self, fn):
  396.         return filter(fn, self.partitions)
  397.  
  398.     def getLogicalPartitions(self):
  399.         """Return a list of logical Partitions on this Disk."""
  400.         return self.__filterPartitions(lambda p: p.active and p.type & parted.PARTITION_LOGICAL)
  401.  
  402.     def getPrimaryPartitions(self):
  403.         """Return a list of primary (or normal) Partitions on this Disk."""
  404.         return self.__filterPartitions(lambda p: p.type == parted.PARTITION_NORMAL)
  405.  
  406.     def getRaidPartitions(self):
  407.         """Return a list of RAID (or normal) Partitions on this Disk."""
  408.         return self.__filterPartitions(lambda p: p.active and p.getFlag(parted.PARTITION_RAID))
  409.  
  410.     def getLVMPartitions(self):
  411.         """Return a list of physical volume-type Partitions on this Disk."""
  412.         return self.__filterPartitions(lambda p: p.active and p.getFlag(parted.PARTITION_LVM))
  413.  
  414.     @localeC
  415.     def getFreeSpaceRegions(self):
  416.         """Return a list of Geometry objects representing the available
  417.            free space regions on this Disk."""
  418.         freespace = []
  419.         part = self.__disk.next_partition()
  420.  
  421.         while part:
  422.             if part.type & parted.PARTITION_FREESPACE:
  423.                 freespace.append(parted.Geometry(PedGeometry=part.geom))
  424.  
  425.             part = self.__disk.next_partition(part)
  426.  
  427.         return freespace
  428.  
  429.     @localeC
  430.     def getFreeSpacePartitions(self):
  431.         """Return a list of Partition objects representing the available
  432.            free space regions on this Disk."""
  433.         freespace = []
  434.         part = self.__disk.next_partition()
  435.  
  436.         while part:
  437.             if part.type & parted.PARTITION_FREESPACE:
  438.                 freespace.append(parted.Partition(disk=self, PedPartition=part))
  439.  
  440.             part = self.__disk.next_partition(part)
  441.  
  442.         return freespace
  443.  
  444.     @localeC
  445.     def getFirstPartition(self):
  446.         """Return the first Partition object on the disk or None if
  447.            there is not one."""
  448.         return parted.Partition(disk=self, PedPartition=self.__disk.next_partition())
  449.  
  450.     @localeC
  451.     def getPartitionByPath(self, path):
  452.         """Return a Partition object associated with the partition device
  453.            path, such as /dev/sda1.  Returns None if no partition is found."""
  454.         for partition in self.partitions:
  455.             if "/dev/%s" % partition.getDeviceNodeName() == path:
  456.                 return partition
  457.  
  458.         return None
  459.  
  460.     def getPedDisk(self):
  461.         """Return the _ped.Disk object contained in this Disk.  For internal
  462.            module use only."""
  463.         return self.__disk
  464.  
  465. # collect all disk types and store them in a hash
  466. diskType = {}
  467. __type = _ped.disk_type_get_next()
  468. diskType[__type.name] = __type
  469.  
  470. while True:
  471.     try:
  472.         __type = _ped.disk_type_get_next(__type)
  473.         diskType[__type.name] = __type
  474.     except:
  475.         break
  476.  
  477. # collect all disk flags and store them in a hash
  478. diskFlag = {}
  479. __flag = _ped.disk_flag_next(0)
  480. diskFlag[__flag] = _ped.disk_flag_get_name(__flag)
  481. __readFlags = True
  482.  
  483. while __readFlags:
  484.     __flag = _ped.disk_flag_next(__flag)
  485.     if not __flag:
  486.         __readFlags = False
  487.     else:
  488.         diskFlag[__flag] = _ped.disk_flag_get_name(__flag)
  489.